﻿using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace anydata.Entitys
{
    public class InstanceData
    {
        private InstanceData()
        {
            fields = new Dictionary<string, List<FormField>>();
            data = new Dictionary<string, List<FormEditData>>();
            infos = new Dictionary<string, FormInfo>();
            node = new WorkNodeModel();

            InitFormCollectionNameMap();
        }

        public static InstanceData Create()
        {
            var instanceData = new InstanceData();
            instanceData.InitFormCollectionNameMap();
            return instanceData;
        }

        public static InstanceData Parse(string json)
        {
            try
            {
                var instanceData = json.ToObject<InstanceData>();
                if (instanceData != null && instanceData.data != null)
                {
                    instanceData.InitFormCollectionNameMap();
                    return instanceData;
                }
                return new InstanceData();
            }
            catch (Exception)
            {
                Debugger.Break();
                throw;
            }

        }

        public async Task<Dictionary<string, List<EntityBase>>> GetThings(IMongoCollection<XTempData> tempCollection)
        {
            var things = new Dictionary<string, List<EntityBase>>();
            foreach (var formId in this.data.Keys)
            {
                things[formId] = new();
                var fields = this.fields.GetValueOrDefault(formId, new List<FormField>());
                var data = this.data.GetValueOrDefault(formId, new List<FormEditData>());
                if (data != null && data.Count > 0 && fields != null && fields.Count > 0)
                {
                    var lastData = data.OrderBy(i => DateTime.Parse(i.createTime)).Last();
                    List<EntityBase> after = new List<EntityBase>();
                    if (!string.IsNullOrEmpty(lastData.afterTempId))
                    {
                        var tempData = await tempCollection.Aggregate().Match(i => i.tempId == lastData.afterTempId && i.isDeleted == false).ToListAsync();
                        after = tempData.Select(a => a.ToEntityBase()).ToList();
                    }
                    else
                    {
                        after = lastData.newData;
                    }
                    foreach (var thing in after)
                    {
                        var values = thing.extensions.ToArray();
                        thing.extensions = new Dictionary<string, object>();
                        thing.labels = new List<string>
                            {
                                "F" + formId
                            };
                        SetThingFields(thing, fields, values);
                        things[formId].Add(thing);
                    }
                }
            }
            return things;
        }

        public static void SetThingFields(in EntityBase thing, List<FormField> fields, KeyValuePair<string, object>[] values)
        {
            foreach (var kp in values)
            {
                var f = fields.Find(i => i.id == kp.Key);
                if (f != null && kp.Value != null)
                {
                    thing.extensions[f.code] = kp.Value;
                    if (f.valueType == "分类型" || f.valueType == "选择型")
                    {
                        string json = kp.Value!.ToString() ?? "";
                        try
                        {
                            var list = JsonConvert.DeserializeObject<List<string>>(json);
                            if (list != null)
                            {
                                foreach (var v in list)
                                {
                                    var item = f.lookups.Find(i => i.value == v?.Trim());
                                    if (item != null)
                                    {
                                        var items = f.recursionItems(item.id);
                                        foreach (var s in items)
                                        {
                                            if (!thing.labels.Contains(s.value))
                                            {
                                                thing.labels.Add(s.value);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch
                        {
                            var item = f.lookups.Find(i => i.value == json);
                            if (item != null)
                            {
                                var items = f.recursionItems(item.id);
                                foreach (var s in items)
                                {
                                    if (!thing.labels.Contains(s.value))
                                    {
                                        thing.labels.Add(s.value);
                                    }
                                }
                            }
                        }
                    }
                }
                else if (kp.Value != null)
                {
                    thing.extensions[kp.Key] = kp.Value;
                }
            }
        }

        void InitFormCollectionNameMap()
        {
            formCollectionNameMap = new();
            var forms = node.AllForms.ToList();
            foreach (var formId in data.Keys)
            {
                var form = forms.FirstOrDefault(f => f.id == formId);
                var collName = form?["collName"] as string;
                if (string.IsNullOrEmpty(collName))
                {
                    collName = DataProvider.ThingCollName;
                }
                formCollectionNameMap[formId] = collName;
            }
            foreach (var info in node.forms)
            {
                if (info != null)
                {
                    infos[info.id] = info;
                }
            }
        }


        public Dictionary<string, List<FormField>> fields { get; set; }
        public Dictionary<string, List<FormEditData>> data { get; set; }
        public WorkNodeModel node { get; set; }

        private Dictionary<string, string> formCollectionNameMap;
        public Dictionary<string, string> FormCollectionNameMap => formCollectionNameMap;
        public Dictionary<string, FormInfo> infos { get; set; }
        public EntityBase? reception { get; set; }
        public EntityBase? assignTask { get; set; }
    }

    public class FormField
    {
        public string id { get; set; }
        public string code { get; set; }
        public string attr { get; set; }
        public string queryRule { get; set; }
        public string valueType { get; set; }
        public bool? isChangeTarget { get; set; }
        public bool? isChangeSource { get; set; }
        public List<LookupModel> lookups { get; set; }
        public List<LookupModel> recursionItems(string id)
        {
            var items = new List<LookupModel>();
            var item = lookups.Find(i => i.id == id);
            if (item != null)
            {
                items.Add(item);
                if (!string.IsNullOrEmpty(item.parentId))
                {
                    items.AddRange(recursionItems(item.parentId));
                }
            }
            return items;
        }
    }

    public class LookupModel
    {
        public string id { get; set; }
        public string code { get; set; }
        public string text { get; set; }
        public string value { get; set; }
        public string parentId { get; set; }
    }

    public class FormEditData
    {
        public JToken before { get; set; }
        public JToken after { get; set; }
        public List<EntityBase> newData => EntityBase.FromJToken(after, creator, out _);
        public string formName { get; set; }
        public string creator { get; set; }
        public string createTime { get; set; }
        public string afterTempId { get; set; }
    }

    public class WorkNodeModel
    {
        public string id { get; set; }
        public string name { get; set; }
        public List<EntityBase> primaryForms { get; set; } = new();
        public List<EntityBase> detailForms { get; set; } = new();
        public List<FormInfo> forms { get; set; } = new();


        public IEnumerable<EntityBase> AllForms
        {
            get
            {
                foreach (var item in primaryForms)
                {
                    yield return item;
                }
                foreach (var item in detailForms)
                {
                    yield return item;
                }
            }
        }
    }

    public class FormInfo
    {
        public string id;
        public bool? closeLock;
    }
}
